#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <unistd.h>
#include <time.h>
#include <sched.h>

#define NB_ITER 100           // 循环次数
#define NB_TASK 2             // 任务数量
#define WORKLOAD_LIMIT 10000000 // 工作负载大小
#define PREEMPTION_COUNT 100   // 抢占次数

// 记录时间的结构体
struct timespec t1, t2, t_diff, max_diff;
long total_diff_sec = 0, total_diff_nsec = 0;  // 用于计算平均延迟

// 模拟工作负载的宏
#define DO_WORKLOAD(i) for (int j = 0; j < (i); j++) { __asm__ volatile("nop"); }

// 获取当前时间
void get_time(struct timespec *ts) {
    clock_gettime(CLOCK_MONOTONIC, ts);
}

void time_diff(struct timespec *start, struct timespec *end, struct timespec *result) {
    // 如果 start 大于 end，直接跳过计算
    if (start->tv_sec > end->tv_sec || (start->tv_sec == end->tv_sec && start->tv_nsec > end->tv_nsec)) {
        return;  // 不进行任何计算
    }

    // 计算时间差
    if ((end->tv_nsec - start->tv_nsec) < 0) {
        result->tv_sec = end->tv_sec - start->tv_sec - 1;
        result->tv_nsec = 1000000000 + end->tv_nsec - start->tv_nsec;
    } else {
        result->tv_sec = end->tv_sec - start->tv_sec;
        result->tv_nsec = end->tv_nsec - start->tv_nsec;
    }
}

// 设置线程优先级
void set_thread_priority(pthread_t thread, int priority) {
    struct sched_param param;
    param.sched_priority = priority;
    if (pthread_setschedparam(thread, SCHED_RR, &param) != 0) {
        perror("Failed to set thread priority");
    }
}

// 普通任务函数（低优先级任务）
void *task(void *arg) {
    int i;
    for (i = 0; i < 10; i++) {
        DO_WORKLOAD(i % WORKLOAD_LIMIT);  // 模拟工作负载
        sched_yield();  // 自愿让出 CPU，模拟线程让步
        printf("2");  // 输出字符 "2"
    }
    
    return NULL;
}

// 高优先级任务函数
void *task_high(void *arg) {
    get_time(&t2);  // 记录高优先级任务开始时的时间
    printf("3");    // 输出字符 "3"
    printf("\n");
    return NULL;
}

// 初始化并启动任务
void *preemptive_initialize_test(void *arg) {
    pthread_t tasks_handle[NB_TASK];
    struct timespec diff;
    max_diff.tv_sec = 0;
    max_diff.tv_nsec = 0;
    
    // 循环进行100次抢占
    for (int i = 0; i < PREEMPTION_COUNT; i++) {
        // 创建低优先级任务线程
        pthread_create(&tasks_handle[0], NULL, task, NULL);
        set_thread_priority(tasks_handle[0], 1); // 设置低优先级任务的优先级

        // 休眠一段时间，确保低优先级任务执行
        usleep(1000);

        // 记录普通任务开始的时间
        get_time(&t1);

        // 创建高优先级任务线程
        pthread_create(&tasks_handle[1], NULL, task_high, NULL);
        set_thread_priority(tasks_handle[1], 99); // 设置高优先级任务的优先级

        // 等待高优先级任务执行完成
        pthread_join(tasks_handle[1], NULL);

        // 计算时间差
        time_diff(&t1, &t2, &t_diff);

        // 记录最大抢占延迟
        if (t_diff.tv_sec > max_diff.tv_sec || 
            (t_diff.tv_sec == max_diff.tv_sec && t_diff.tv_nsec > max_diff.tv_nsec)) {
            max_diff.tv_sec = t_diff.tv_sec;
            max_diff.tv_nsec = t_diff.tv_nsec;
        }

        // 累加所有抢占延迟，用于计算平均值
        total_diff_sec += t_diff.tv_sec;
        total_diff_nsec += t_diff.tv_nsec;

        // 处理纳秒部分可能大于1秒的情况
        if (total_diff_nsec >= 1000000000) {
            total_diff_sec += 1;
            total_diff_nsec -= 1000000000;
        }

        // 等待低优先级任务线程结束
        pthread_join(tasks_handle[0], NULL);
    }

    // 输出最大抢占延迟
    printf("\nMax preemption delay: %ld seconds and %ld nanoseconds\n", max_diff.tv_sec, max_diff.tv_nsec);
    
    // 计算并输出平均抢占延迟
    long avg_diff_sec = total_diff_sec / PREEMPTION_COUNT;
    long avg_diff_nsec = total_diff_nsec / PREEMPTION_COUNT;
    printf("Average preemption delay: %ld seconds and %ld nanoseconds\n", avg_diff_sec, avg_diff_nsec);

    return NULL;
}

int main() {
    // 创建并启动初始化测试线程
    pthread_t test_thread;
    pthread_create(&test_thread, NULL, preemptive_initialize_test, NULL);

    // 等待测试线程完成
    pthread_join(test_thread, NULL);

    return 0;
}

